import { useEffect, useRef, useState } from 'react'

import empty from '../../images/empty.png'

import './index.less'

export type ColumnType<T> = {
  title: string
  key: string
  render?(value: any, record: T, index: number): React.ReactNode
  width?: number
  align?: 'left' | 'center' | 'right'
  style?(value: any, record: T, index: number): React.CSSProperties
  hidden?(): boolean
}

export interface ListRankingProps<T> {
  dataSource: any[]
  columns: ColumnType<T>[]
  rowKey?: string
  rowStyle?: React.CSSProperties
  autoScroll?: boolean
  delay?: number
  rgbColor?: string
  depReset?: any[]
  emptyText?: React.ReactNode
}

export default function ListRanking<T = any>(props: ListRankingProps<T>) {
  const {
    dataSource,
    columns,
    rowKey,
    autoScroll = false,
    delay = 3000,
    rgbColor,
    depReset = [],
    rowStyle,
    emptyText
  } = props
  const containerRef = useRef<HTMLDivElement>(null)
  const rowRef = useRef<HTMLDivElement>(null)
  const [fresh, refresh] = useState(0)
  const timer = useRef<NodeJS.Timeout>()

  useEffect(() => {
    const rowHeight = rowRef.current?.clientHeight
    const containerHeight = containerRef.current?.clientHeight
    let minScrollCount = 999
    if (rowHeight && containerHeight) {
      minScrollCount = Math.floor(containerHeight / rowHeight)
    }
    if (!autoScroll || dataSource.length <= minScrollCount) return
    timer.current = setInterval(() => {
      requestAnimationFrame(() => {
        if (
          containerRef.current!.scrollTop >=
          containerRef.current!.scrollHeight - containerHeight!
        ) {
          containerRef.current!.scrollTo(0, 0)
          return
        }
        containerRef.current!.scrollTo(
          0,
          containerRef.current!.scrollTop + rowHeight!
        )
      })
    }, delay)
    return () => {
      timer.current && clearInterval(timer.current)
    }
  }, [dataSource, autoScroll, delay, fresh, ...depReset])

  useEffect(() => {
    containerRef.current?.scrollTo(0, 0)
  }, [...depReset])

  return (
    <div className="list-ranking">
      <div className="list-ranking-header">
        {columns
          .filter((column) => column.hidden?.() ?? true)
          .map((column) => {
            return (
              <div
                key={column.key}
                style={{
                  width: column.width,
                  textAlign: column.align || 'left'
                }}
              >
                {column.title}
              </div>
            )
          })}
      </div>
      <div
        className="list-ranking-body"
        ref={containerRef}
        onMouseEnter={() => {
          timer.current && clearInterval(timer.current)
        }}
        onMouseLeave={() => {
          refresh(Math.random())
        }}
      >
        {dataSource.length ? (
          <div id="scroll-container">
            <div
              style={
                rgbColor
                  ? {
                      background: `linear-gradient(315deg, rgba(${rgbColor},0) 0%, rgba(${rgbColor},0.08) 100%)`,
                      border: '1px solid',
                      borderImage: `linear-gradient(45deg, rgba(${rgbColor}, 0.02), rgba(${rgbColor}, 0.09)) 1 1`,
                      borderRadius: 2
                    }
                  : {}
              }
            >
              {dataSource.slice(0, 3).map((item, index) => {
                return (
                  <RowRender<T>
                    innerRef={rowRef}
                    key={rowKey ? item[rowKey] : index}
                    data={item}
                    columns={columns}
                    index={index}
                    style={rowStyle}
                  />
                )
              })}
            </div>
            {dataSource.slice(3).map((item, index) => {
              const i = index + 3
              return (
                <RowRender<T>
                  key={rowKey ? item[rowKey] : i}
                  data={item}
                  columns={columns}
                  index={i}
                  style={rowStyle}
                />
              )
            })}
          </div>
        ) : (
          <div className="flexc juc alc" style={{ height: '100%', gap: 8 }}>
            <img src={empty} style={{ width: 32, height: 32 }} />
            <span style={{ opacity: 0.32 }}>{emptyText || '暂无数据'}</span>
          </div>
        )}
      </div>
    </div>
  )
}

type ListRankingItemProps<T> = {
  data: any
  columns: ColumnType<T>[]
  index: number
  style?: React.CSSProperties
  innerRef?: React.RefObject<HTMLDivElement>
}

function RowRender<T = any>({
  data,
  columns,
  index,
  style,
  innerRef
}: ListRankingItemProps<T>) {
  return (
    <div className="list-ranking-row" style={style} ref={innerRef}>
      {columns
        .filter((column) => column.hidden?.() ?? true)
        .map((column) => {
          const cellStyle = column.style?.(data[column.key], data, index) || {}
          return (
            <div
              key={column.key}
              style={{
                width: column.width,
                textAlign: column.align || 'left',
                ...cellStyle
              }}
            >
              {isFunction(column.render)
                ? column.render!(data[column.key], data, index)
                : (data[column.key] ?? '--')}
            </div>
          )
        })}
    </div>
  )
}

function isFunction(value: any) {
  return (
    typeof value === 'function' ||
    Object.prototype.toString.call(value) === '[object Function]' ||
    value instanceof Function
  )
}
